home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / devClientDev.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  15KB  |  534 lines

  1. /* 
  2.  * devClientDev.c --
  3.  *
  4.  *    This file contains the code for the kernel to interact with
  5.  *    a user process via a device.  This is used to keep track of
  6.  *    currently active client machines of the server's kernel.
  7.  *
  8.  * Copyright 1989 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/devClientDev.c,v 9.3 92/12/13 18:11:54 mgbaker Exp $ SPRITE (Berkeley)";
  20. #endif /* not lint */
  21.  
  22. #include <sprite.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <sync.h>
  26. #include <devClientDev.h>
  27. #include <procTypes.h>
  28. #include <timer.h>
  29. #include <fsioDevice.h>
  30. #include <recov.h>
  31. #include <fsutil.h>
  32.  
  33. #define    MAX_INDEX 100
  34.  
  35. typedef struct    DeviceState {
  36.     Dev_ClientInfo    toUserQueue[MAX_INDEX];        /* Data to daemon. */
  37.     Dev_ClientInfo    toKernelQueue[MAX_INDEX];    /* Data from daemon. */
  38.     int            userUnreadIndex;        /* Unread by daemon. */
  39.     int            userUnusedIndex;        /* Unwritten by os. */
  40.     int            kernelUnreadIndex;        /* Unread by os. */
  41.     int            kernelUnusedIndex;        /* Unwritten by d. */
  42.     Fs_NotifyToken    dataReadyToken;            /* Read/write notify. */
  43.     Sync_Condition    waitForDaemon;            /* Wait for daemon. */
  44.     Boolean        recovInProgress;        /* Only one instance. */
  45.     Boolean        waitingForRecov;        /* Condition check. */
  46.     Sync_Condition    waitForRecovResponse;        /* Wait for reopen to
  47.                              * client to return. */
  48. } DeviceState;
  49.  
  50. static Boolean        deviceOpen = FALSE;
  51. static Fs_Device    *theDevicePtr = (Fs_Device *) NULL;
  52. #define    INC_QUEUEPTR(theIndex)    \
  53.     ((theIndex) == (MAX_INDEX - 1) ? (theIndex) = 0 :  (theIndex)++)
  54. int            currentUnreadIndex;
  55.  
  56.  
  57. /*
  58.  * Need to do something about queue suddenly becoming empty because it's
  59.  * all filled up!
  60.  */
  61.  
  62. static    Sync_Lock    clientStateLock;
  63. #define    LOCKPTR        (&clientStateLock)
  64.  
  65.  
  66. /*
  67.  *----------------------------------------------------------------------
  68.  *
  69.  * DevClientStateOpen --
  70.  *
  71.  *    For the user process to open the device by which it communicates
  72.  *    with the kernel about clients.
  73.  *
  74.  * Results:
  75.  *    Return status.
  76.  *
  77.  * Side effects:
  78.  *    State for device set up.  Process created that will cause kernel
  79.  *    to start recovering.
  80.  *
  81.  *----------------------------------------------------------------------
  82.  */
  83. /*ARGSUSED*/
  84. ReturnStatus
  85. DevClientStateOpen(devicePtr, useFlags, data, flagsPtr)
  86.     Fs_Device        *devicePtr;    /* Device info. */
  87.     int            useFlags;    /* Flags from stream being opened. */
  88.     Fs_NotifyToken    data;        /* Call-back for input notification. */
  89.     int            *flagsPtr;    /* OUT: Device flags. */
  90. {
  91.     DeviceState        *statePtr;
  92.  
  93.     LOCK_MONITOR;
  94.     printf("Opening client state device.\n");
  95.     if (deviceOpen) {
  96.     printf("Client state device already open.\n");
  97.     UNLOCK_MONITOR;
  98.     return FS_FILE_BUSY;
  99.     }
  100.     theDevicePtr = devicePtr;
  101.     if ((useFlags & FS_USER) == 0) {
  102.     printf("DevClientStateOpen should only  be called by a user proc.\n");
  103.     UNLOCK_MONITOR;
  104.     return GEN_INVALID_ARG;
  105.     }
  106.     statePtr = (DeviceState *) malloc(sizeof (DeviceState));
  107.     devicePtr->data = (ClientData) statePtr;
  108.     statePtr->userUnreadIndex = 0;
  109.     statePtr->userUnusedIndex = 0;
  110.     statePtr->dataReadyToken = data;
  111.     statePtr->recovInProgress = FALSE;
  112.     statePtr->waitingForRecov = FALSE;
  113.  
  114.     /*
  115.      * We're receiving recovery list from user-level daemon if the device
  116.      * is opened for write as well as read.
  117.      */
  118.     if (useFlags & FS_WRITE) {
  119.     Recov_InitServerDriven();
  120.     }
  121.     deviceOpen = TRUE;
  122.     /* Should put in timeout here for getting recov info from client daemon. */
  123.     UNLOCK_MONITOR;
  124.     return SUCCESS;
  125. }
  126.  
  127. /*
  128.  *----------------------------------------------------------------------
  129.  *
  130.  * DevClientStateClose --
  131.  *
  132.  *    Close the device so it can be reopened.
  133.  *
  134.  * Results:
  135.  *    Return status.
  136.  *
  137.  * Side effects:
  138.  *    Free space and such.
  139.  *
  140.  *----------------------------------------------------------------------
  141.  */
  142. /*ARGSUSED*/
  143. ReturnStatus
  144. DevClientStateClose(devicePtr, useFlags, openCount, writerCount)
  145.     Fs_Device        *devicePtr;    /* Device info. */
  146.     int            useFlags;    /* Flags from stream being opened. */
  147.     int            openCount;
  148.     int            writerCount;
  149. {
  150.     LOCK_MONITOR;
  151.     printf("Closing client state device.\n");
  152.     if (!deviceOpen) {
  153.     printf("Client state device already closed.\n");
  154.     UNLOCK_MONITOR;
  155.     return SUCCESS;
  156.     }
  157.     free((char *) devicePtr->data);
  158.  
  159.     deviceOpen = FALSE;
  160.     Recov_StopServerDriven();
  161.     UNLOCK_MONITOR;
  162.     return SUCCESS;
  163. }
  164.  
  165.  
  166. /*
  167.  *----------------------------------------------------------------------
  168.  *
  169.  * DevClientStateRead --
  170.  *
  171.  *    A user process reads info from kernel on device about client states.
  172.  *
  173.  * Results:
  174.  *    SUCCESS        - if info was found in the queue.  
  175.  *    FS_WOULD_BLOCK    - no info found.
  176.  *
  177.  * Side effects:
  178.  *    Removes some of the info from the queue.
  179.  *
  180.  *----------------------------------------------------------------------
  181.  */
  182. /*ARGSUSED*/
  183. ReturnStatus
  184. DevClientStateRead(devicePtr, readPtr, replyPtr)
  185.     Fs_Device    *devicePtr;
  186.     Fs_IOParam    *readPtr;    /* Read parameter block */
  187.     Fs_IOReply    *replyPtr;    /* Return length and signal */ 
  188. {
  189.     ReturnStatus    status = SUCCESS;
  190.     register DeviceState    *statePtr;
  191.  
  192.     LOCK_MONITOR;
  193.  
  194.     statePtr = (DeviceState *) devicePtr->data;
  195.     if (statePtr->userUnreadIndex == statePtr->userUnusedIndex) {
  196.     status = FS_WOULD_BLOCK;
  197.     UNLOCK_MONITOR;
  198.     return status;
  199.     }
  200.  
  201.     if (sizeof (Dev_ClientInfo) > readPtr->length) {
  202.     status = GEN_INVALID_ARG;
  203.     UNLOCK_MONITOR;
  204.     return status;
  205.     }
  206.     bcopy(&(statePtr->toUserQueue[statePtr->userUnreadIndex]), readPtr->buffer,
  207.         sizeof (Dev_ClientInfo));
  208.  
  209.     replyPtr->length = sizeof (Dev_ClientInfo);
  210.     INC_QUEUEPTR(statePtr->userUnreadIndex);
  211.     UNLOCK_MONITOR;
  212.     return(status);
  213. }
  214.  
  215. /*
  216.  *----------------------------------------------------------------------
  217.  *
  218.  * DevClientStateWrite --
  219.  *
  220.  *    A user process writes info to kernel on device about state of hosts
  221.  *    before crash.
  222.  *
  223.  * Results:
  224.  *    SUCCESS or invalid arg.
  225.  *
  226.  * Side effects:
  227.  *    Removes some of the info from the queue.
  228.  *
  229.  *----------------------------------------------------------------------
  230.  */
  231. /*ARGSUSED*/
  232. ReturnStatus
  233. DevClientStateWrite(devicePtr, writePtr, replyPtr)
  234.     Fs_Device    *devicePtr;
  235.     Fs_IOParam    *writePtr;    /* Write parameter block */
  236.     Fs_IOReply    *replyPtr;    /* Return length and signal */ 
  237. {
  238.     ReturnStatus        status = SUCCESS;
  239.     register DeviceState    *statePtr;
  240.  
  241.     LOCK_MONITOR;
  242.  
  243.     statePtr = (DeviceState *) devicePtr->data;
  244.     if (statePtr->recovInProgress) {
  245.     panic("DevClientStateWrite: only one instance of recovery allowed.\n");
  246.     }
  247.     if (writePtr->offset != 0) {
  248.     printf("DevClientStateWrite: write offset didn't start at 0: %d.\n",
  249.         writePtr->offset);
  250.     }
  251.     if ((writePtr->length % sizeof (Dev_ClientInfo)) != 0) {
  252.     printf(
  253.     "DevClientStateWrite: Write info not multiple of client structure.\n");
  254.     UNLOCK_MONITOR;
  255.     return GEN_INVALID_ARG;
  256.     }
  257.  
  258.     statePtr->recovInProgress = TRUE;
  259.     bcopy(writePtr->buffer, &(statePtr->toKernelQueue[0]), writePtr->length);
  260.     statePtr->kernelUnreadIndex = 0;
  261.     statePtr->kernelUnusedIndex = writePtr->length / sizeof (Dev_ClientInfo);
  262.     if (statePtr->kernelUnusedIndex > MAX_INDEX) {
  263.     panic("DevClientStateWrite: too many clients!\n");
  264.     }
  265.  
  266.     Recov_ServerStartingRecovery();
  267.     while (statePtr->kernelUnreadIndex != statePtr->kernelUnusedIndex) {
  268.     int    clientID;
  269.  
  270.     clientID =
  271.         statePtr->toKernelQueue[statePtr->kernelUnreadIndex].hostNumber;
  272.     if (statePtr->toKernelQueue[statePtr->kernelUnreadIndex].hostState !=
  273.         DEV_CLIENT_STATE_NEW_HOST) {
  274.         panic("DevClientStateWrite: Bad host state from daemon.");
  275.     }
  276.     Recov_MarkDoingServerRecovery(clientID);
  277.     status = Fsutil_DoServerRecovery(clientID);
  278. #ifdef NOTDEF
  279.     XX Mark going through recovery.
  280.     Proc_CallFunc(Fsutil_DoServerRecovery, (ClientData) clientID, 0);
  281.     statePtr->waitingForRecov = TRUE;
  282.     while (statePtr->waitingForRecov) {
  283.         (void) Sync_Wait(&(statePtr->waitForRecovResponse), FALSE);
  284.     }
  285.     XX Mark not going through recovery.
  286. #endif NOTDEF
  287.     Recov_UnmarkDoingServerRecovery(clientID);
  288.  
  289.     INC_QUEUEPTR(statePtr->kernelUnreadIndex);
  290.     }
  291.     Recov_ServerFinishedRecovery();
  292.  
  293.     statePtr->recovInProgress = FALSE;
  294.     replyPtr->length = writePtr->length;
  295.     UNLOCK_MONITOR;
  296.  
  297.     return SUCCESS;
  298. }
  299.  
  300. /*
  301.  *----------------------------------------------------------------------
  302.  *
  303.  * Dev_ClientStateWakeRecovery --
  304.  *
  305.  *    Call-back for another module to rewaken us for us to keep on
  306.  *    doing recovery.
  307.  *
  308.  * Results:
  309.  *    None.
  310.  *
  311.  * Side effects:
  312.  *    Wakeup signal.
  313.  *
  314.  *----------------------------------------------------------------------
  315.  */
  316. void
  317. Dev_ClientStateWakeRecovery()
  318. {
  319.     DeviceState        *statePtr;
  320.  
  321.     statePtr = (DeviceState *) theDevicePtr->data;
  322.     statePtr->waitingForRecov = FALSE;
  323.     Sync_Broadcast(&(statePtr->waitForRecovResponse));
  324.  
  325.     return;
  326. }
  327.     
  328.  
  329. /*
  330.  *----------------------------------------------------------------------
  331.  *
  332.  * DevClientStateIOControl --
  333.  *
  334.  *    For the device to tell the kernel it is done processing client state.
  335.  *
  336.  * Results:
  337.  *    SUCCESS        - the operation was successful.
  338.  *    SYS_INVALID_ARG - bad command, or wrong buffer size.
  339.  *
  340.  * Side effects:
  341.  *    None.
  342.  *
  343.  *----------------------------------------------------------------------
  344.  */
  345. /*ARGSUSED*/
  346. ReturnStatus
  347. DevClientStateIOControl(devicePtr, ioctlPtr, replyPtr)
  348.     Fs_Device    *devicePtr;
  349.     Fs_IOCParam *ioctlPtr;
  350.     Fs_IOReply *replyPtr;
  351.  
  352. {
  353.     DeviceState        *statePtr;
  354.     ReturnStatus    status = SUCCESS;
  355.     int            numEntries;
  356.  
  357.     statePtr = (DeviceState *) (devicePtr->data);
  358.  
  359.     switch (ioctlPtr->command) {
  360.     case DEV_CLIENT_START_LIST:
  361.     /*
  362.      * Write out state of hosts as we know it to user process.
  363.      * To do this, we put stuff into the queue starting with a
  364.      * DEV_CLIENT_START_LIST and ending with a DEV_CLIENT_END_LIST
  365.      * so that the user process knows when it has the whole list.
  366.      */
  367.     numEntries = Recov_GetCurrentHostStates(&(statePtr->toUserQueue[1]),
  368.         MAX_INDEX - 2);
  369.     if (numEntries < 0) {
  370.         panic("DevClientStateIOControl: too many hosts for buffer.");
  371.     }
  372.     statePtr->toUserQueue[0].hostState = DEV_CLIENT_START_LIST;
  373.     statePtr->userUnreadIndex = 0;
  374.     statePtr->userUnusedIndex = numEntries + 2;
  375.     statePtr->toUserQueue[numEntries + 1].hostState = DEV_CLIENT_END_LIST;
  376.  
  377.     break;
  378.     case DEV_CLIENT_END_LIST:
  379.     /* Show that daemon did read data and poked us about it. */
  380.     Sync_Broadcast(&(statePtr->waitForDaemon));
  381.     break;
  382.     default:
  383.     break;
  384.     }
  385.  
  386.     return status;
  387. }
  388.  
  389. /*
  390.  *----------------------------------------------------------------------
  391.  *
  392.  * TimeoutFunc
  393.  *
  394.  *    The user-level daemon hasn't responded quickly enough in writing
  395.  *    our state to disk.  It's probably dead.  Since this must all
  396.  *    happen synchronously, we panic.
  397.  *
  398.  * Results:
  399.  *    None.
  400.  *
  401.  * Side effects:
  402.  *    May panic.
  403.  *
  404.  *----------------------------------------------------------------------
  405.  */
  406. static void
  407. TimeoutFunc(clientData, callInfoPtr)
  408.     ClientData        clientData;
  409.     Proc_CallInfo    *callInfoPtr;
  410. {
  411.     DeviceState        *statePtr;
  412.  
  413.     statePtr = (DeviceState *) theDevicePtr->data;
  414.  
  415.     LOCK_MONITOR;
  416.     if (!deviceOpen) {
  417.     UNLOCK_MONITOR;
  418.     return;
  419.     }
  420.     if (statePtr->userUnreadIndex == currentUnreadIndex) {
  421.     printf("Timeout func for host state device called:\n");
  422.     printf("\tcurrentUnreadIndex is still %d, userUnreadIndex %d\n",
  423.         currentUnreadIndex, statePtr->userUnreadIndex);
  424.     UNLOCK_MONITOR;
  425.     panic("User-level daemon must be dead.");
  426.     }
  427.     UNLOCK_MONITOR;
  428.     return;
  429. }
  430.  
  431. /*
  432.  *----------------------------------------------------------------------
  433.  *
  434.  * Dev_ClientHostUp
  435.  *
  436.  *    Tell daemon process to record the fact that another client is
  437.  *    talking with us.
  438.  *
  439.  * Results:
  440.  *    None.
  441.  *
  442.  * Side effects:
  443.  *    Talk to user process.
  444.  *
  445.  *----------------------------------------------------------------------
  446.  */
  447. void
  448. Dev_ClientHostUp(spriteID)
  449.     int        spriteID;
  450. {
  451.     DeviceState    *statePtr;
  452.  
  453.     LOCK_MONITOR;
  454.     if (!deviceOpen) {
  455.     UNLOCK_MONITOR;
  456.     return;
  457.     }
  458.     statePtr = (DeviceState *) theDevicePtr->data;
  459.     statePtr->toUserQueue[statePtr->userUnusedIndex].hostNumber = spriteID;
  460.     statePtr->toUserQueue[statePtr->userUnusedIndex].hostState =
  461.         DEV_CLIENT_STATE_NEW_HOST;
  462.  
  463.     INC_QUEUEPTR(statePtr->userUnusedIndex);
  464.     currentUnreadIndex = statePtr->userUnreadIndex;
  465.     Fsio_DevNotifyReader(statePtr->dataReadyToken);
  466.     /*
  467.      * This test is good enough if the daemon promises to read all
  468.      * available data whenever it reads data.  We also set a timer in
  469.      * case the user-level daemon has died and doesn't respond.
  470.      */
  471.     Proc_CallFunc(TimeoutFunc, (ClientData) theDevicePtr,
  472.         5 * timer_IntOneSecond);
  473.     while (statePtr->userUnreadIndex == currentUnreadIndex) {
  474.     (void) Sync_Wait(&(statePtr->waitForDaemon), FALSE);
  475.     }
  476.     UNLOCK_MONITOR;
  477.     return;
  478. }
  479.  
  480. /*
  481.  *----------------------------------------------------------------------
  482.  *
  483.  * Dev_ClientHostDown
  484.  *
  485.  *    Tell daemon process to record the fact that a client that was
  486.  *    talking with us has died.
  487.  *
  488.  * Results:
  489.  *    None.
  490.  *
  491.  * Side effects:
  492.  *    Talk to user process.
  493.  *
  494.  *----------------------------------------------------------------------
  495.  */
  496. void
  497. Dev_ClientHostDown(spriteID)
  498.     int        spriteID;
  499. {
  500.     DeviceState    *statePtr;
  501.  
  502.     LOCK_MONITOR;
  503.     if (!deviceOpen) {
  504.     UNLOCK_MONITOR;
  505.     return;
  506.     }
  507.     statePtr = (DeviceState *) theDevicePtr->data;
  508.     statePtr->toUserQueue[statePtr->userUnusedIndex].hostNumber = spriteID;
  509.     statePtr->toUserQueue[statePtr->userUnusedIndex].hostState =
  510.         DEV_CLIENT_STATE_DEAD_HOST;
  511.  
  512.     INC_QUEUEPTR(statePtr->userUnusedIndex);
  513.     currentUnreadIndex = statePtr->userUnreadIndex;
  514.     Fsio_DevNotifyReader(statePtr->dataReadyToken);
  515.     /*
  516.      * This test is good enough if the daemon promises to read all
  517.      * available data whenever it reads data.  We also set a timer in
  518.      * case the user-level daemon has died and doesn't respond.
  519.      */
  520. #ifdef NOTDEF
  521. XX Increase timeout time?  Or make timeout function understand that
  522. if client is still marked as going through recovery, it should allow more
  523. time?
  524. #endif NOTDEF
  525.     printf("userUnread and currentUnread at %d\n", currentUnreadIndex);
  526.     Proc_CallFunc(TimeoutFunc, (ClientData) theDevicePtr,
  527.         5 * timer_IntOneSecond);
  528.     while (statePtr->userUnreadIndex == currentUnreadIndex) {
  529.     (void) Sync_Wait(&(statePtr->waitForDaemon), FALSE);
  530.     }
  531.     UNLOCK_MONITOR;
  532.     return;
  533. }
  534.